#include "game.hh"

/// La limite de boutons visibles dans l'interface
const unsigned int MAX_VISIBLE_BUTTONS = 3;

Game::Game() {
  this->showFullScreen();

  QPalette palette;
  palette.setBrush(this->backgroundRole(), QBrush(QImage(":/resources/menu/menu.png")));
  this->setPalette(palette);

  mainLayout_ = 0;
  mainLayout_ = new QVBoxLayout();

  QLabel *title = new QLabel("Bug Odyssey");
  title->setStyleSheet("font-size: 100px");

  QPushButton *button1 = new QPushButton("Continuer");
  button1->setStyleSheet("QPushButton { padding: 10px }");
  QPushButton *button2 = new QPushButton("Nouvelle Partie");
  button2->setStyleSheet("QPushButton { padding: 10px }");
  QPushButton *button3 = new QPushButton("Quitter");
  button3->setStyleSheet("QPushButton { padding: 10px }");

  mainLayout_->addWidget(title, 0, Qt::AlignCenter);
  mainLayout_->addWidget(button1, 0, Qt::AlignCenter);
  mainLayout_->addWidget(button2, 0, Qt::AlignCenter);
  mainLayout_->addWidget(button3, 0, Qt::AlignCenter);

  connect(button1, SIGNAL(clicked()), this, SLOT(clickcontinuer()));
  connect(button2, SIGNAL(clicked()), this, SLOT(clicknouvelle()));
  connect(button3, SIGNAL(clicked()), this, SLOT(clickquitter()));

  listwidgets_.push_back(title);
  listwidgets_.push_back(button1);
  listwidgets_.push_back(button2);
  listwidgets_.push_back(button3);

  countSelectorItem_ = 0;

  /// -1 signifie "aucun item de l'inventaire selectionne"
  selectedIndexItem_ = -1;

  isDialogMode_ = false;

  /// Initialisation du vecteur de visages

  faces_["ARISTIDE_NORMAL"] = new QGraphicsPixmapItem(QPixmap(QString(":/resources/faces/aristide1.png")));
  faces_["ARISTIDE_SAD"] = new QGraphicsPixmapItem(QPixmap(QString(":/resources/faces/aristide2.png")));
  faces_["ARISTIDE_HAPPY"] = new QGraphicsPixmapItem(QPixmap(QString(":/resources/faces/aristide3.png")));
  faces_["ARISTIDE_ANGRY"] = new QGraphicsPixmapItem(QPixmap(QString(":/resources/faces/aristide4.png")));
  faces_["ARISTIDE_IMPRESSED"] = new QGraphicsPixmapItem(QPixmap(QString(":/resources/faces/aristide5.png")));
  faces_["ARISTIDE_OBJECTION"] = new QGraphicsPixmapItem(QPixmap(QString(":/resources/faces/aristide6.png")));
  faces_["ARISTIDE_THINKING"] = new QGraphicsPixmapItem(QPixmap(QString(":/resources/faces/aristide7.png")));
  faces_["ARISTIDE_KO"] = new QGraphicsPixmapItem(QPixmap(QString(":/resources/faces/aristide8.png")));

  faces_["MARTY_UNCONVINCED"] = new QGraphicsPixmapItem(QPixmap(QString(":/resources/faces/marty1.png")));
  faces_["MARTY_NORMAL"] = new QGraphicsPixmapItem(QPixmap(QString(":/resources/faces/marty2.png")));
  faces_["MARTY_HAPPY"] = new QGraphicsPixmapItem(QPixmap(QString(":/resources/faces/marty3.png")));
  faces_["MARTY_SMILE"] = new QGraphicsPixmapItem(QPixmap(QString(":/resources/faces/marty4.png")));
  faces_["MARTY_FEAR"] = new QGraphicsPixmapItem(QPixmap(QString(":/resources/faces/marty5.png")));
  faces_["MARTY_DISTURBED"] = new QGraphicsPixmapItem(QPixmap(QString(":/resources/faces/marty6.png")));
  faces_["MARTY_BORED"] = new QGraphicsPixmapItem(QPixmap(QString(":/resources/faces/marty7.png")));
  faces_["MARTY_ANGRY"] = new QGraphicsPixmapItem(QPixmap(QString(":/resources/faces/marty8.png")));

  faces_["YIN_THINKING"] = new QGraphicsPixmapItem(QPixmap(QString(":/resources/faces/yin1.png")));
  faces_["YIN_STRESSED"] = new QGraphicsPixmapItem(QPixmap(QString(":/resources/faces/yin2.png")));
  faces_["YIN_HAPPY"] = new QGraphicsPixmapItem(QPixmap(QString(":/resources/faces/yin3.png")));
  faces_["YIN_ANGRY"] = new QGraphicsPixmapItem(QPixmap(QString(":/resources/faces/yin4.png")));
  faces_["YIN_OUTRAGED"] = new QGraphicsPixmapItem(QPixmap(QString(":/resources/faces/yin5.png")));
  faces_["YIN_NORMAL"] = new QGraphicsPixmapItem(QPixmap(QString(":/resources/faces/yin6.png")));
  faces_["YIN_FEAR"] = new QGraphicsPixmapItem(QPixmap(QString(":/resources/faces/yin7.png")));
  faces_["YIN_DISTURBED"] = new QGraphicsPixmapItem(QPixmap(QString(":/resources/faces/yin8.png")));

  faces_["CAILLEUX"] = new QGraphicsPixmapItem(QPixmap(QString(":/resources/faces/cailleux.png")));
  faces_["FEROX"] = new QGraphicsPixmapItem(QPixmap(QString(":/resources/faces/ferox.png")));
  faces_["SEPIA"] = new QGraphicsPixmapItem(QPixmap(QString(":/resources/faces/sepia.png")));

  faces_["VIDE"] = new QGraphicsPixmapItem(QPixmap(QString(":/resources/faces/vide.png")));

  /// Mise en place du layout principal
  this->setLayout(mainLayout_);

  this->show();
}

// gestion des clics du menu
void Game::clickcontinuer()
{
  QDialog *chargement = new QDialog();
  chargement->setFixedSize(300, 300);
  chargement->setWindowTitle("Chargement");

  // QSignalMapper
  QSignalMapper* mapper = new QSignalMapper(chargement);
  connect(mapper, SIGNAL(mapped(QString)), this, SLOT(loadgamenb(QString)));

  QLabel *texte = new QLabel("Charger une partie");

  QVBoxLayout *layout = new QVBoxLayout();
  layout->addWidget(texte, 0, Qt::AlignCenter);
  QList<QString> savelist = ResourceLoader::extractsave();
  for (int i = 0; i < savelist.count(); i++)
  {
    // do something
    QStringList savedata = savelist.operator [](i).split("^");
    QString text = savedata.operator [](0);
    QPushButton *s1 = new QPushButton(text);
    s1->setFixedWidth(150);
    mapper->setMapping(s1, savelist.operator [](i));
    connect(s1, SIGNAL(clicked()), mapper, SLOT(map()));
    connect(s1, SIGNAL(clicked()), chargement, SLOT(accept()));
    layout->addWidget(s1, 0, Qt::AlignCenter);
  }

  QPushButton *ann = new QPushButton("Annuler");
  connect(ann, SIGNAL(clicked()), chargement, SLOT(reject()));
  layout->addWidget(ann, 0, Qt::AlignCenter);
  chargement->setLayout(layout);
  if (chargement->exec() == QDialog::Accepted)
    chargement->close();
}

void Game::clicknouvelle()
{
  QDialog *playername = new QDialog();
  playername->setWindowTitle("Nom du joueur");
  QLabel *text = new QLabel("Entrez votre nom");
  QLineEdit *name = new QLineEdit("");
  QPushButton *ok = new QPushButton("OK");
  QPushButton *ann = new QPushButton("Annuler");
  connect(ok, SIGNAL(clicked()), playername, SLOT(accept()));
  connect(ann, SIGNAL(clicked()), playername, SLOT(reject()));

  QVBoxLayout *layout = new QVBoxLayout();
  layout->addWidget(text, 0, Qt::AlignCenter);
  layout->addWidget(name);
  QHBoxLayout *okann = new QHBoxLayout();
  okann->addWidget(ok);
  okann->addWidget(ann);
  layout->addLayout(okann);

  playername->setLayout(layout);
  if (playername->exec() == QDialog::Accepted)
  {
    player_.setName(name->text().toStdString());
    playername->close();
    foreach (QWidget* w, listwidgets_)
    {
      mainLayout_->removeWidget(w);
      delete w;
    }
    delete mainLayout_;
    // pour generer un id unique
    idGame_ = QDateTime::currentDateTime().toString("yyyyMMddhhmmss").toStdString();
    idCurrentRoom_ = 0;
    this->SetUp();
  }
}

void Game::clickquitter()
{
  QDialog *exit = new QDialog();
  exit->setWindowTitle("Quitter");

  QLabel *texte = new QLabel("Voulez-vous vraiment quitter ?");
  QPushButton *oui = new QPushButton("Oui");
  QPushButton *non = new QPushButton("Non");

  connect(oui, SIGNAL(clicked()), exit, SLOT(accept()));
  connect(non, SIGNAL(clicked()), exit, SLOT(reject()));

  QVBoxLayout *layout_txt = new QVBoxLayout();
  layout_txt->addWidget(texte, 0, Qt::AlignCenter);
  QHBoxLayout *layout_btn = new QHBoxLayout();
  layout_btn->addWidget(oui);
  layout_btn->addWidget(non);
  layout_txt->addLayout(layout_btn);

  exit->setLayout(layout_txt);
  if (exit->exec() == QDialog::Accepted)
    this->close();
}

void Game::loadgamenb(QString s)
{
  QStringList savedata = s.split("^");
  player_.setName(savedata.operator [](0).split(" -").operator [](0).toStdString());
  QStringList iddata = savedata.operator [](1).split("%");
  idGame_ = iddata.operator [](0).toStdString();
  idCurrentRoom_ = iddata.operator [](1).toInt();
  std::list<int> itemlist = ResourceLoader::getPlayerItems(idGame_);
  while (itemlist.size() > 0)
  {
    player_.addItem(itemlist.front());
    itemlist.pop_front();
  }

  foreach (QWidget* w, listwidgets_)
  {
    mainLayout_->removeWidget(w);
    delete w;
  }
  delete mainLayout_;
  this->SetUp();
}


void Game::SetUp(){

  /// Mise en place du fond du jeu
  QPalette palette;
  palette.setBrush(this->backgroundRole(), QBrush(QImage(":/resources/menu/background.png")));
  this->setPalette(palette);

  /// Initialisation de l'interface
  mainLayout_ = 0;
  mainLayout_ = new QVBoxLayout();
  actionBar_ = 0;
  actionBar_ = new QGridLayout();

  actionButtons_.insert(std::pair<std::string, QPushButton*> ("give", new QPushButton("Donner")));
  actionButtons_.insert(std::pair<std::string, QPushButton*> ("open", new QPushButton("Ouvrir")));
  actionButtons_.insert(std::pair<std::string, QPushButton*> ("close", new QPushButton("Fermer")));
  actionButtons_.insert(std::pair<std::string, QPushButton*> ("take", new QPushButton("Prendre")));
  actionButtons_.insert(std::pair<std::string, QPushButton*> ("look", new QPushButton("Regarder")));
  actionButtons_.insert(std::pair<std::string, QPushButton*> ("talk", new QPushButton("Parler")));
  actionButtons_.insert(std::pair<std::string, QPushButton*> ("use", new QPushButton("Utiliser")));
  actionButtons_.insert(std::pair<std::string, QPushButton*> ("push", new QPushButton("Pousser")));
  actionButtons_.insert(std::pair<std::string, QPushButton*> ("pull", new QPushButton("Tirer")));

  std::map<std::string, QPushButton*>::iterator actionButtonIter;

  for (actionButtonIter = actionButtons_.begin() ; actionButtonIter != actionButtons_.end(); actionButtonIter++) {
    (*actionButtonIter).second->setFixedSize(.1* this->width(), .09* this->height());
    (*actionButtonIter).second->setStyleSheet("font-size:20px");
    (*actionButtonIter).second->setEnabled(false);
  }

  itemButtons_.insert(std::pair<int, QPushButton*> (1, new QPushButton("")));
  itemButtons_.insert(std::pair<int, QPushButton*> (2, new QPushButton("")));
  itemButtons_.insert(std::pair<int, QPushButton*> (3, new QPushButton("")));

  std::map<int, QPushButton*>::iterator itemButtonIter;

  for (itemButtonIter = itemButtons_.begin(); itemButtonIter != itemButtons_.end(); itemButtonIter++) {
    (*itemButtonIter).second->setFixedSize(.1* this->width(), .1* this->width());
    (*itemButtonIter).second->setEnabled(false);
  }

  b_PreviousItem_ = new QPushButton("");
  b_PreviousItem_->setIcon(QIcon(":/resources/interface/left.png"));
  b_PreviousItem_->setFixedSize(.07* this->width(), .07* this->width());
  b_PreviousItem_->setIconSize(QSize(120, 120));
  b_NextItem = new QPushButton("");
  b_NextItem->setIcon(QIcon(":/resources/interface/right.png"));
  b_NextItem->setFixedSize(.07* this->width(), .07* this->width());
  b_NextItem->setIconSize(QSize(120, 120));

  /// Bouton Quitter
  b_Quit_ = new QPushButton("Quitter");
  b_Quit_->setToolTip(QString("Quitter le jeu"));
  b_Quit_->setFixedSize(.07* this->width(), .07* this->width());
  connect(b_Quit_, SIGNAL(clicked()), this, SLOT(clickquitter()));

  actionBar_->addWidget(actionButtons_["give"], 0, 0);
  actionBar_->addWidget(actionButtons_["open"], 1, 0);
  actionBar_->addWidget(actionButtons_["close"], 2, 0);
  actionBar_->addWidget(actionButtons_["take"], 0, 1);
  actionBar_->addWidget(actionButtons_["look"], 1, 1);
  actionBar_->addWidget(actionButtons_["talk"], 2, 1);
  actionBar_->addWidget(actionButtons_["use"], 0, 2);
  actionBar_->addWidget(actionButtons_["push"], 1, 2);
  actionBar_->addWidget(actionButtons_["pull"], 2, 2);

  actionBar_->addWidget(b_PreviousItem_, 1, 3);
  actionBar_->addWidget(b_NextItem, 1, 7);
  actionBar_->addWidget(b_Quit_, 1, 8);

  actionBar_->addWidget(itemButtons_[1], 0, 4, 3, 1);
  actionBar_->addWidget(itemButtons_[2], 0, 5, 3, 1);
  actionBar_->addWidget(itemButtons_[3], 0, 6, 3, 1);

  scene_.setSceneRect(scene_.itemsBoundingRect());

  view_ = 0;
  view_ = new QGraphicsView(&scene_);
  view_->setSceneRect(scene_.sceneRect());
  view_->installEventFilter(this);

  /// Initialisation de la zone de dialogue

  proxyDialogZone_ = 0;
  nextDialogButton_ = new QPushButton("Suivant");
  nextDialogButton_->setFixedSize(75, 75);
  dialogCurrentFace_ = 0;

  dialogZone_ = 0;

  connect(nextDialogButton_, SIGNAL(clicked()), this, SLOT(executeNextDialog()));

  /// Initlialisation de la barre d'actions et connextion des widgets a leurs slots
  connect(this, SIGNAL(clickScene(int, int)), this, SLOT(resolveSceneClick(int, int)));

  connect(actionButtons_["give"], SIGNAL(clicked()), this, SLOT(clickGive()));
  connect(actionButtons_["open"], SIGNAL(clicked()), this, SLOT(clickOpen()));
  connect(actionButtons_["close"], SIGNAL(clicked()), this, SLOT(clickClose()));
  connect(actionButtons_["take"], SIGNAL(clicked()), this, SLOT(clickTake()));
  connect(actionButtons_["look"], SIGNAL(clicked()), this, SLOT(clickLook()));
  connect(actionButtons_["talk"], SIGNAL(clicked()), this, SLOT(clickTalk()));
  connect(actionButtons_["use"], SIGNAL(clicked()), this, SLOT(clickUse()));
  connect(actionButtons_["push"], SIGNAL(clicked()), this, SLOT(clickPush()));
  connect(actionButtons_["pull"], SIGNAL(clicked()), this, SLOT(clickPull()));

  /// Clic sur bouton = appel clickItemButton(id du bouton)
  QSignalMapper* itemClickedMapper = new QSignalMapper(this);
  for (int cptBtn = 1; cptBtn < 4; cptBtn++) {
    itemClickedMapper->setMapping(itemButtons_[cptBtn], cptBtn);
    connect(itemButtons_[cptBtn], SIGNAL(clicked()), itemClickedMapper, SLOT(map()));
  }
  connect(itemClickedMapper, SIGNAL(mapped(int)), this, SLOT(clickItemButton(int)));

  /// QSignalMapper
  QSignalMapper* mapper = new QSignalMapper(this);
  connect(mapper, SIGNAL(mapped(int)), this, SLOT(clickUpDown(int)));
  mapper->setMapping(b_PreviousItem_, -1);
  mapper->setMapping(b_NextItem, 1);
  connect(b_PreviousItem_, SIGNAL(clicked()), mapper, SLOT(map()));
  connect(b_NextItem, SIGNAL(clicked()), mapper, SLOT(map()));

  /// Association des layouts
  view_->setFixedSize(.95 * this->width(), .7 * this->height());
  mainLayout_->setProperty("padding", 0);
  mainLayout_->setProperty("margin", 0);

  mainLayout_->addWidget(view_, 1, Qt::AlignJustify);
  mainLayout_->addLayout(actionBar_, 1);
  mainLayout_->setSpacing(0);
  mainLayout_->setMargin(0);
  this->setLayout(mainLayout_);

  this->show();
  this->run();
}

void Game::loadItems() {
  unsigned int i;

  for (i = 1; i <= MAX_VISIBLE_BUTTONS; i++) {
    itemButtons_[i]->setEnabled(true);
  }

  for (i = 0; ((i < player_.getVectorItem().size()) && (i < MAX_VISIBLE_BUTTONS)); i++) {
    itemButtons_[i + 1]->setIcon(QPixmap(QString::fromStdString(player_.getVectorItem().at((countSelectorItem_) + i).getImgSrc())));
    itemButtons_[i + 1]->setToolTip(QString(player_.getVectorItem().at((countSelectorItem_) + i).getName().c_str()));
    itemButtons_[i + 1]->setIconSize(QSize(150, 150));
  }

  if (i < MAX_VISIBLE_BUTTONS) {
    while (i < MAX_VISIBLE_BUTTONS) {
      itemButtons_[i + 1]->setEnabled(false);
      i += 1;
    }
  }

  if ((player_.getVectorItem().size() > countSelectorItem_ + MAX_VISIBLE_BUTTONS)) {
    b_NextItem->setEnabled(true);
  }
  else {
    b_NextItem->setEnabled(false);
  }

  /// Si l'inventaire ne comporte aucun objet on ne peut pas revenir en arriere
  if (countSelectorItem_ != 0) {
    b_PreviousItem_->setEnabled(true);
  } else {
    b_PreviousItem_->setEnabled(false);
  }

}

void Game::cleanRoom() {
  unsigned int index_room;
  unsigned int index_element;
  unsigned int index_textEvent;

  /// Pour chaque salle -une seule en fait est stockee- ...
  for (index_room = 0; index_room < vectorRoom_.size(); index_room++) {
    /// ... on supprime chaque Element alloue dynamiquement car issu du XML ...
    for (index_element = 0; index_element < vectorRoom_.at(index_room).getVectorElements().size(); index_element++) {
      delete (vectorRoom_.at(index_room)).getVectorElements().at(index_element);
    }

    /// ... et on fait la meme chose pour les textes
    for (index_textEvent = 0; index_textEvent < vectorRoom_.at(index_room).getVectorTextEvents().size(); index_textEvent++) {
      delete (vectorRoom_.at(index_room)).getVectorTextEvents().at(index_textEvent);
    }
  }
}

  /// Les pointeurs widgets attaches a la fenetre sont supprimes a sa destruction
Game::~Game(){
  cleanRoom();
}

Player Game::getPlayer() {
  return player_;
}

std::string Game::getIdGame() {
  return idGame_;
}

int Game::getCountSelectorItem() {
  return countSelectorItem_;
}

int Game::getIdCurrentRoom() {
  return idCurrentRoom_;
}

std::vector<Room> Game::getVectorRoom() {
  return vectorRoom_;
}

bool Game::isEligibleAction(Room* curRoom, int textEventId) {
  unsigned int index = 0;

  /// Boucle sur TextEvent de la salle en cherchant si l'evenement n'a pas de dependance
  for (index = 0; index != curRoom->getVectorTextEvents().size(); index++)  {
    if (curRoom->getVectorTextEvents().at(index)->getId() == textEventId) {
      if (curRoom->getVectorTextEvents().at(index)->getRequiredTextEventId() == 0) {
        /// Pas de dependance
        return true;
      }
      else {
        /// On verifie si la dependance est satisfaite en bouclant sur les evenements deja faits
        unsigned int indexPastEvents = 0;
        for (indexPastEvents = 0; indexPastEvents != getPlayer().getPastEvents().size(); indexPastEvents++) {
          if (getPlayer().getPastEvents().at(indexPastEvents) == curRoom->getVectorTextEvents().at(
                index)->getRequiredTextEventId()) {
            return true;
          }
        }
        /// L'evenement a une dependance non resolue
        return false;
      }
    }
  }
  /// On n'a pas trouve l'evenement (ce qui implique une erreur dans le xml)
  return false;
}

void Game::disableActionButtons() {
  std::map<std::string, QPushButton*>::iterator actionButtonIter;

  for (actionButtonIter = actionButtons_.begin() ; actionButtonIter != actionButtons_.end(); actionButtonIter++) {
    (*actionButtonIter).second->setEnabled(false);
  }
}

void Game::disableInterfaceButtons() {
  disableActionButtons();

  b_PreviousItem_->setEnabled(false);
  b_NextItem->setEnabled(false);

  for (unsigned int indexBtn = 1; indexBtn <= MAX_VISIBLE_BUTTONS; indexBtn++) {
    itemButtons_[indexBtn]->setEnabled(false);
  }

}

void Game::assignCurrentRoom(Room** ptr) {
  try {
    *ptr = getCurrentRoom(idCurrentRoom_);
    if (*ptr == 0) {
      std::string err = "Salle actuelle non trouvee";
      throw err;
    }
  }
  catch (const std::string& e) {
    std::cout << e << std::endl;
    // appel clean
    exit(-4);
  }
}

void Game::resolveSceneClick(int x, int y) {
  QGraphicsItem* clickedElt = scene_.itemAt(QPointF(QPoint(x, y)));

  Room* currentRoom = 0;
  assignCurrentRoom(&currentRoom);

  /**
    Si le dialogue est en cours il ne faut pas reagir au clic
    sur element de la scene. Il faut que seul le clic sur le
    bouton de dialogue suivant soit effectif (pris en compte
    dans le connect du bouton)
  */
  if (!isDialogMode_) {
    /// annulation selection de l'inventaire au cas ou on aurait selectionne un Item juste avant
    selectedIndexItem_ = -1;

    /// Cliquer sur le fond annule la selection d'element
    if (clickedElt == &background_) {

      std::map<QGraphicsPixmapItem*, Element*>::iterator resetOpa;
      for (resetOpa = poolGraphicalElements_.begin(); resetOpa != poolGraphicalElements_.end();
           resetOpa++) {
        resetOpa->first->setOpacity(1.0);
      }

      currentRoom->setSelectedElement(0);
      disableActionButtons();
    }
    else {
      /// Si le joueur reclique sur le meme element on ne fait rien
      if (currentRoom->getSelectedElement() != poolGraphicalElements_[(QGraphicsPixmapItem*)clickedElt]) {
        disableActionButtons();

        currentRoom->setSelectedElement(poolGraphicalElements_[(QGraphicsPixmapItem*)clickedElt]);

        if (currentRoom->getSelectedElement() != 0) {
          /// Permet d'eviter de mettre en opaque plusieurs elements
          std::map<QGraphicsPixmapItem*, Element*>::iterator resetOpa;
          for (resetOpa = poolGraphicalElements_.begin(); resetOpa != poolGraphicalElements_.end();
               resetOpa++) {
            resetOpa->first->setOpacity(1.0);
          }
          clickedElt->setOpacity(0.75);
        }

        std::map<std::string, int> mapEltActions = currentRoom->getSelectedElement()->getActionDispatcher().getActions();
        std::map<std::string, int>::iterator iter;

        for (iter = mapEltActions.begin(); iter != mapEltActions.end(); iter++) {
          /// Une action est eligible si l'evenement qu'elle declenche n'a pas de dependance
          if (isEligibleAction(currentRoom, (*iter).second)) {
            actionButtons_[(*iter).first]->setEnabled(true);
          }
        }
      }
    }
  }
}

bool Game::eventFilter(QObject *obj, QEvent *event) {
  if((obj == (this->view_)) && (event->type() == QEvent::MouseButtonPress))
  {
    QMouseEvent* mouseEvent = (QMouseEvent*)event;
    emit clickScene(mouseEvent->x(), mouseEvent->y());
    return true;
  }
  return QObject::eventFilter(obj, event);
}

void Game::manageTextEvent(TextEvent* currentTextEvent)
{
  if (currentTextEvent->getAddItemId() != 0) {
    player_.addItem(currentTextEvent->getAddItemId());
  }

  /// Si objet perdu reinitialisation de la vue de l'inventaire
  if (currentTextEvent->getConsumeItemId() != 0) {
    std::string strItemToRemove = player_.consumeItem(currentTextEvent->getConsumeItemId());
    countSelectorItem_ = 0;

    /// On vient d'effacer l'Item dans player.listItem donc il faut effacer son image dans l'inventaire

    for (unsigned int idx = 1; idx <= MAX_VISIBLE_BUTTONS; idx++) {
      if (itemButtons_[idx]->toolTip() == QString(strItemToRemove.c_str())) {
        itemButtons_[idx]->setIcon(QIcon());
        itemButtons_[idx]->setToolTip("");
      }
    }
  }

  if ((currentTextEvent->getAddItemId() != 0) || (currentTextEvent->getConsumeItemId() != 0)) {
    loadItems();
  }
}

void Game::manageFaceTextEvent(TextEvent* curTextEvent) {
  if (!curTextEvent->getFace().empty()) {
    scene_.removeItem(dialogCurrentFace_);
    dialogCurrentFace_ = faces_[curTextEvent->getFace()];
    dialogCurrentFace_->setZValue(10);
    scene_.addItem(dialogCurrentFace_);

    /// Pour changer la position du visage pendant les dialogues sur l'ecran
    dialogCurrentFace_->setPos(200, 100);
  }
}

void Game::manageMessage(int idTextEvent, Room* currentRoom) {
  player_.addPastEvent(idTextEvent);

  TextEvent* currentTextEvent = 0;

  unsigned int iText = 0;
  for (iText = 0; iText < currentRoom->getVectorTextEvents().size(); iText++) {
    if (currentRoom->getVectorTextEvents().at(iText)->getId() == idTextEvent) {
      currentTextEvent = currentRoom->getVectorTextEvents().at(iText);
      break;
    }
  }
  if ((iText == currentRoom->getVectorTextEvents().size()) || (currentTextEvent == 0)) {
    /// Parcours des TextEvent sans trouver id voulu OU recupere TextEvent nul (bug non connu et non prevu mais potentiel)
    exit(-5);
  }

  manageTextEvent(currentTextEvent);

  manageFaceTextEvent(currentTextEvent);

  isDialogMode_ = true;

  if (dialogZone_ == 0) {

    dialogZone_ = new QLabel();
    //dialogZone_->setFont(QFont(QString("Volter (Goldfish)")));

    dialogZoneLayout_ = new QHBoxLayout();
    dialogZoneLayout_->addWidget(dialogZone_);
    dialogZoneLayout_->addWidget(nextDialogButton_);

    dialogSceneContainer_ = new QWidget();
    dialogSceneContainer_->setLayout(dialogZoneLayout_);
    dialogSceneContainer_->setGeometry(100, 307, 800, 125);

    proxyDialogZone_ = scene_.addWidget(dialogSceneContainer_);
    proxyDialogZone_->setZValue(10);
  }

  dialogZone_->setText(QString(currentTextEvent->getText().c_str()));
  proxyDialogZone_->setVisible(true);
  proxyDialogZone_->setZValue(10);

  gNextTextEventId_ = currentTextEvent->getNextEventId();
  gNextRoomId_ = currentTextEvent->getNextRoomId();

  disableInterfaceButtons();

}

void Game::displayMessage(std::string actionKey){  
  Room* currentRoom = 0;
  assignCurrentRoom(&currentRoom);

  int idTextEvent;
  /// Recuperer id du TextEvent differement selon selection Element OU Item par le joueur
  if (selectedIndexItem_ != -1) {
    idTextEvent = player_.getVectorItem().at(selectedIndexItem_).getActionDispatcher().getActions()[actionKey];
    /// On a recupere le TextEvent plus besoin de connaitre l'index de l'objet selectionne de l'inventaire
    selectedIndexItem_ = -1;
  }
  else {
    idTextEvent = currentRoom->getSelectedElement()->getActionDispatcher().getActions()[actionKey];
    /// Plus besoin de connaitre l'Element selectionne car on a le texte necessaire

    std::map<QGraphicsPixmapItem*, Element*>::iterator resetOpa;
    for (resetOpa = poolGraphicalElements_.begin(); resetOpa != poolGraphicalElements_.end();
         resetOpa++) {
      resetOpa->first->setOpacity(1.0);
    }
    currentRoom->setSelectedElement(0);
  }

  manageMessage(idTextEvent, currentRoom);

  /*
  player_.addPastEvent(idTextEvent);

  /// Recuperer le contenu a afficher

  TextEvent* currentTextEvent = 0;

  unsigned int iText = 0;
  for (iText = 0; iText < currentRoom->getVectorTextEvents().size(); iText++) {
    if (currentRoom->getVectorTextEvents().at(iText)->getId() == idTextEvent) {
      currentTextEvent = currentRoom->getVectorTextEvents().at(iText);
      break;
    }
  }
  if ((iText == currentRoom->getVectorTextEvents().size()) || (currentTextEvent == 0)) {
    /// Parcours des TextEvent sans trouver id voulu OU recupere TextEvent nul (bug non connu et non prevu mais potentiel)
    exit(-5);
  }

  /// Gestion de l'inventaire suite au message
  manageTextEvent(currentTextEvent);

  /// Gestion de l'affichage du visage suite au message
  manageFaceTextEvent(currentTextEvent);

  isDialogMode_ = true;

  if (dialogZone_ == 0) {
    dialogZone_ = new QLabel();

    dialogZoneLayout_ = new QHBoxLayout();
    dialogZoneLayout_->addWidget(dialogZone_);
    dialogZoneLayout_->addWidget(nextDialogButton_);

    dialogSceneContainer_ = new QWidget();
    dialogSceneContainer_->setLayout(dialogZoneLayout_);

    proxyDialogZone_ = scene_.addWidget(dialogSceneContainer_);
  }

  dialogZone_->setText(QString(currentTextEvent->getText().c_str()));
  proxyDialogZone_->setVisible(true);

  /// Si texte multiple son id sera recupere dans le slot executeNextDialog()
  gNextTextEventId_ = currentTextEvent->getNextEventId();
  gNextRoomId_ = currentTextEvent->getNextRoomId();
  /// Desactivation boutons interface
  disableInterfaceButtons();
  */
}

void Game::addRoom(Room& room)
{
  vectorRoom_.push_back(room);
}

void Game::run() {

  /// Si on est au debut du jeu on force le deplacement a la premiere salle
  if (idCurrentRoom_ == 0) {
    idCurrentRoom_ = 1;
  }

  Room roomToPopulate(idCurrentRoom_);

  ResourceLoader::loadRoom(&roomToPopulate);
  loadItems();

  /// roomToPopulate contient toutes ses infos + ses TextEvent + ses Element
  this->addRoom(roomToPopulate);

  /// Maintenant il faut afficher le contenu de la salle
  render();

  // fait une sauvegarde quand on charge la partie
  /*if (roomToPopulate.getIsSave())
    ResourceLoader::SaveGame(this->getIdGame(), this->getIdCurrentRoom(), this->getPlayer().getName(), this->getPlayer().getVectorItem());*/
  /// Si il y a un evenement a lancer au demarrage de la scene
  if (roomToPopulate.getAutoTextEventId() != 0) {
    Room* currentRoom = 0;
    assignCurrentRoom(&currentRoom);

    manageMessage(roomToPopulate.getAutoTextEventId(), currentRoom);
/*
    player_.addPastEvent(roomToPopulate.getAutoTextEventId());

    TextEvent* currentTextEvent = 0;

    unsigned int iText = 0;
    for (iText = 0; iText < currentRoom->getVectorTextEvents().size(); iText++) {
      if (currentRoom->getVectorTextEvents().at(iText)->getId() == roomToPopulate.getAutoTextEventId()) {
        currentTextEvent = currentRoom->getVectorTextEvents().at(iText);
        break;
      }
    }
    if ((iText == currentRoom->getVectorTextEvents().size()) || (currentTextEvent == 0)) {
      /// On a a parcouru le vecteur des TextEvent sans trouver un objet avec id voulu ou on a recupere un objet nul (bug non connu et non prevu mais potentiel)
      exit(-5);
    }

    /// se charge de l'inventaire
    manageTextEvent(currentTextEvent);

    manageFaceTextEvent(currentTextEvent);

    isDialogMode_ = true;

    dialogZone_->setText(QString(currentTextEvent->getText().c_str()));

    gNextTextEventId_ = currentTextEvent->getNextEventId();
    gNextRoomId_ = currentTextEvent->getNextRoomId();

    disableInterfaceButtons();
*/
  }
}

Room* Game::getCurrentRoom(int idRoom) {
  for (unsigned int i = 0; i < vectorRoom_.size(); i++) {
    if (vectorRoom_.at(i).getId() == idRoom) {
      return &(vectorRoom_.at(i));
    }
  }
  return 0;
}

void Game::render() {
  /// On recupere la Room idCurrentRoom -id de la salle dans laquelle on se trouve-
  Room* currentRoom = 0;
  assignCurrentRoom(&currentRoom);

  background_.setPixmap(QPixmap(currentRoom->getImgSrc().c_str()));
  this->scene_.addItem(&background_);
  view_->fitInView(&background_);

  unsigned int i;
  for (i=0; i < currentRoom->getVectorElements().size(); i++) {
    QGraphicsPixmapItem* pixElt = 0;
    pixElt = new QGraphicsPixmapItem(QPixmap(QString((currentRoom->getVectorElements().at(i))->getImgSrc().c_str())));

    poolGraphicalElements_.insert(std::pair<QGraphicsPixmapItem*, Element*>(pixElt, (currentRoom->getVectorElements().at(i))));

    this->scene_.addItem(pixElt);
    pixElt->setPos(currentRoom->getVectorElements().at(i)->getX(), currentRoom->getVectorElements().at(i)->getY());
  }

}

/// SLOTS
void Game::executeNextDialog() {
  Room* currentRoom = 0;
  assignCurrentRoom(&currentRoom);

  if (gNextTextEventId_ != 0) {
    TextEvent* currentTextEvent = 0;

    unsigned int iText = 0;

    for (iText = 0; iText < currentRoom->getVectorTextEvents().size(); iText++) {
      if (currentRoom->getVectorTextEvents().at(iText)->getId() == gNextTextEventId_) {
        currentTextEvent = currentRoom->getVectorTextEvents().at(iText);
        break;
      }
    }
    if ((iText == currentRoom->getVectorTextEvents().size()) || (currentTextEvent == 0)) {
      /// On a a parcouru le vecteur des TextEvent sans trouver un objet avec id voulu ou on a recupere un objet nul (bug non connu et non prevu mais potentiel)
      exit(-5);
    }

    /// on ajoute l'evenement a la liste des events passes
    player_.addPastEvent(gNextTextEventId_);

    manageTextEvent(currentTextEvent);

    manageFaceTextEvent(currentTextEvent);

    /// on a le nouveau dialogue dans currentTextEvent
    dialogZone_->setText(QString(currentTextEvent->getText().c_str()));
    gNextTextEventId_ = currentTextEvent->getNextEventId();
    gNextRoomId_ = currentTextEvent->getNextRoomId();
  }
  else {
    /// Retirer la zone de dialogue et retourner a l'etat normal
    proxyDialogZone_->setVisible(false);
    if (dialogCurrentFace_) {
      /// Si il y a un visage on le cache
      dialogCurrentFace_->setVisible(false);
    }
    isDialogMode_ = false;

    /// Quand le dialogue est termine il faut reactiver les objets de l'inventaire
    loadItems();

    /// Si il y a un changement de salle on le fait ici
    if (gNextRoomId_ != 0) {

      /// On retire les elements interactifs
      for (std::map<QGraphicsPixmapItem*, Element*>::iterator iter = poolGraphicalElements_.begin();
           iter!= poolGraphicalElements_.end(); ) {
        scene_.removeItem(iter->first); /// On retire l'element de la scene
        delete iter->first; /// On libere la memoire prise par l'image de l'element
        poolGraphicalElements_.erase(iter); /// On retire le couple de la map
        iter = poolGraphicalElements_.begin();
      }

      /// On retire le background de la piece
      scene_.removeItem(&background_);

      /// On supprime les Element et TextEvent alloues de la salle
      this->cleanRoom();

      /// On efface la salle precedente de la liste des salles
      vectorRoom_.erase(vectorRoom_.begin());

      /// On genere la nouvelle salle
      Room roomToPopulate(gNextRoomId_);

      ResourceLoader::loadRoom(&roomToPopulate);

      this->addRoom(roomToPopulate);

      idCurrentRoom_ = gNextRoomId_;

      render();

      if (roomToPopulate.getIsSave())
        ResourceLoader::SaveGame(this->getIdGame(), this->getIdCurrentRoom(), this->getPlayer().getName(), this->getPlayer().getVectorItem());
      /// Si il y a un evenement a lancer au demarrage de la scene
      if (roomToPopulate.getAutoTextEventId() != 0) {

        manageMessage(roomToPopulate.getAutoTextEventId(), currentRoom);
        //Room* currentRoom = 0;
        //if ((currentRoom = getCurrentRoom(idCurrentRoom_)) == 0) {
        //  exit(-4);
        //}
/*
        player_.addPastEvent(roomToPopulate.getAutoTextEventId());

        TextEvent* currentTextEvent = 0;

        unsigned int iText = 0;
        for (iText = 0; iText < currentRoom->getVectorTextEvents().size(); iText++) {
          if (currentRoom->getVectorTextEvents().at(iText)->getId() == roomToPopulate.getAutoTextEventId()) {
            currentTextEvent = currentRoom->getVectorTextEvents().at(iText);
            break;
          }
        }
        if ((iText == currentRoom->getVectorTextEvents().size()) || (currentTextEvent == 0)) {
          /// On a a parcouru le vecteur des TextEvent sans trouver un objet avec id voulu ou on a recupere un objet nul (bug non connu et non prevu mais potentiel)
          exit(-5);
        }


        /// se charge de l'inventaire
        manageTextEvent(currentTextEvent);

        manageFaceTextEvent(currentTextEvent);

        isDialogMode_ = true;

        dialogZone_->setText(QString(currentTextEvent->getText().c_str()));

        gNextTextEventId_ = currentTextEvent->getNextEventId();
        gNextRoomId_ = currentTextEvent->getNextRoomId();

        proxyDialogZone_->setVisible(true);

        disableInterfaceButtons();
*/
      }
    }
  }
}

void Game::clickGive()
{
    displayMessage("give");
}

void Game::clickOpen()
{
    displayMessage("open");
}

void Game::clickClose()
{
    displayMessage("close");
}

void Game::clickTake()
{
    displayMessage("take");
}

void Game::clickLook()
{
    displayMessage("look");
}

void Game::clickTalk()
{
    displayMessage("talk");
}

void Game::clickUse()
{
    displayMessage("use");
}

void Game::clickPush()
{
    displayMessage("push");
}

void Game::clickPull()
{
    displayMessage("pull");
}

void Game::clickItemButton(int idPushButton) {
  /// Desactivation des boutons d'action
  disableActionButtons();

  /**
    les boutons retournent une valeur entre 1 et 3 donc il faut faire un -1 a la formule
    pour recuperer la liste des actions possible
  */
  std::map<std::string, int> mapSelectedItemActions =
      player_.getVectorItem().at(countSelectorItem_ + idPushButton - 1).getActionDispatcher().getActions();

  selectedIndexItem_ = countSelectorItem_ + idPushButton - 1;

  Room* currentRoom = 0;
  assignCurrentRoom(&currentRoom);

  /// on regarde si pour chaque evenement declenchable...
  for(std::map<std::string, int>::iterator mIter = mapSelectedItemActions.begin();
      mIter != mapSelectedItemActions.end(); mIter++) {
    /// ...le text_event appelable par l'objet de l'inventaire est charge dans les text_events de la salle
    if (isEligibleAction(currentRoom, mIter->second)) {
      actionButtons_[mIter->first]->setEnabled(true);
    }
  }
}

void Game::clickUpDown(int value)
{
  if ((player_.getVectorItem().size() > countSelectorItem_ + MAX_VISIBLE_BUTTONS) ||
      ((countSelectorItem_ != 0) && (value == -1))) {
    countSelectorItem_ += value;
    loadItems();
  }
}
